﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Web;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
using AL.Common;
using AL.Models;
using AL.Web;


namespace AL.Service
{
    /// <summary>
    /// 权限、异常拦截筛选器（基于 ActionFilterAttribute 机制）[ 增加了 IExceptionFilter 异常拦截处理 ]
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public class PermissionFilterAttribute : ActionFilterAttribute, IExceptionFilter
    {

        #region 　< 异常拦截 IExceptionFilter OnException >　

        /// <summary>
        /// 异常拦截 （接口 IExceptionFilter 的实现）
        /// </summary>
        /// <param name="filterContext"></param>
        public void OnException(ExceptionContext filterContext) {
            //获取异常信息，入库保存（暂未实现保存）
            Exception Error = filterContext.Exception;
            string Message = Error.Message;//错误信息
            string Url = HttpContext.Current.Request.RawUrl;//错误发生地址

            // 标记异常已处理
            filterContext.ExceptionHandled = true;

            if (filterContext.HttpContext.Request.IsAjaxRequest()) {
                filterContext.HttpContext.Response.StatusCode = 501;
                filterContext.Result = new System.Web.Mvc.JsonResult() { ContentEncoding = System.Text.Encoding.UTF8, ContentType = "application/json", Data = new { IsError = true, Message = Message, Data = 501 }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
            } else {
                // 跳转到错误页
                filterContext.Result = new RedirectResult("/Error/?url=" + HttpUtility.UrlEncode(Url) + "&msg=" + HttpUtility.UrlEncode(Message));//跳转至错误提示页面
            }
        }

        #endregion


        /// <summary>
        /// 权限拦截
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext == null) {
                throw new ArgumentNullException("filterContext");
            }


            // 接下来进行权限拦截与验证
            object[] attrs = filterContext.ActionDescriptor.GetCustomAttributes(typeof(CheckUserRoleAttribute), true);
            var isCheckUserRolePage = attrs.Length == 1;// 当前Action请求是否为具体的功能页


            // 验证当前Action是否是匿名访问Action
            if (CheckAnonymous(filterContext)) {
                return;
            }

            // 未登录验证
            //if (SessionHelper.Get("UserID") == null) {
            if (!System.Web.HttpContext.Current.User.Identity.IsAuthenticated) {
                // 执行退出
                var app = filterContext.HttpContext.ApplicationInstance as MvcApplication;
                var action = app.GetUnityContainer().Resolve<IFormsAuthenticationService>();
                action.SignOut();
                // 跳转到登录页面
                filterContext.RequestContext.HttpContext.Response.Redirect("~/Admin/Login");
                return;
            }
            // 验证当前Action是否是登录就可以访问的Action
            if (CheckLoginAllow(filterContext)) {
                return;
            }


            if (this.AuthorizeCore(filterContext) == false)// 根据验证判断进行处理
            {
                // 注：如果未登录直接在URL输入功能权限地址提示不是很友好；如果登录后输入未维护的功能权限地址，那么也可以访问，这个可能会有安全问题
                if (isCheckUserRolePage == true) {
                    // 跳转到登录页面
                    //filterContext.RequestContext.HttpContext.Response.Redirect("~/OAuth/Login");
                    filterContext.RequestContext.HttpContext.Response.Redirect("~/Admin/Login");
                } else {

                    if (filterContext.HttpContext.Request.IsAjaxRequest()) {
                        filterContext.HttpContext.Response.StatusCode = 403;

                        filterContext.Result = new System.Web.Mvc.JsonResult() { ContentEncoding = System.Text.Encoding.UTF8, ContentType = "application/json", Data = new { IsError = true, Data = 403, Message = "您没有权限" }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
                    } else {
                        // 权限验证不通过，同时又不是需要验证用户权限的页面（转到错误页面，提示您访问的页面尚未配置权限）
                        filterContext.RequestContext.HttpContext.Response.Redirect("~/Error/ErrorPermission");
                    }
                }

            }
        }




        /// <summary>
        /// //权限判断业务逻辑
        /// </summary>
        /// <param name="filterContext"></param>
        /// <param name="isViewPage">是否是页面</param>
        /// <returns></returns>
        protected virtual bool AuthorizeCore(ActionExecutingContext filterContext)
        {

            if (filterContext.HttpContext == null) {
                throw new ArgumentNullException("httpContext");
            }
            
            //// 取消高级权限验证
            //return true;

            // 下面开始用户权限验证 ==================================================
            var controllerName = filterContext.RouteData.Values["controller"].ToString();
            var actionName = filterContext.RouteData.Values["action"].ToString();
            var actionMethod = filterContext.RequestContext.HttpContext.Request.HttpMethod.ToUpper();

            var app = filterContext.HttpContext.ApplicationInstance as MvcApplication;
            //所有被维护的Action权限
            //var actions = app.GetUnityContainer().Resolve<IActionPermissionService>().GetActionPermissions();

            var userName = System.Web.HttpContext.Current.User.Identity.Name;
            if (userName.ToUpper() == "HAVENT" || userName.ToUpper() == "ADMIN") return true;

            var userService = app.GetUnityContainer().Resolve<IUserService>();
            userService.ProxyCreationEnabled = true;
            var user = userService.GetUser(userName);

            ////如果当前Action属于被维护的Action权限
            //if (actions.Count(a => a.ControllerName.ToLower() == controllerName.ToLower() && a.ActionName.ToLower() == actionName.ToLower() && a.ActionMethod.ToLower() == actionMethod.ToLower()) != 0) {

            //    foreach (Role item in user.Roles) {

            //        if (item.ActionPermissions.Count(a => a.ControllerName.ToLower() == controllerName.ToLower() && a.ActionName.ToLower() == actionName.ToLower() && a.ActionMethod.ToLower() == actionMethod.ToLower()) != 0) {
            //            return true;
            //        }

            //    }

            //}


            // 默认不允许
            return false;
        }



        #region 　< CheckAnonymous / CheckLoginAllow 验证是否为 匿名标记 / 登录许可标记 >　

        /// <summary>
        /// [Anonymous标记]验证是否匿名访问
        /// </summary>
        /// <param name="filterContext"></param>
        /// <returns></returns>
        public bool CheckAnonymous(ActionExecutingContext filterContext)
        {
            // 验证是否是匿名访问的Action
            object[] attrsAnonymous = filterContext.ActionDescriptor.GetCustomAttributes(typeof(AnonymousAttribute), true);
            // 是否是Anonymous
            var Anonymous = attrsAnonymous.Length == 1;
            return Anonymous;
        }
        /// <summary>
        /// [LoginAllow标记]验证是否登录就可以访问(如果已经登陆,那么不对于标识了LoginAllow的方法就不需要验证了)
        /// </summary>
        /// <param name="filterContext"></param>
        /// <returns></returns>
        public bool CheckLoginAllow(ActionExecutingContext filterContext)
        {
            // 在这里允许一种情况,如果已经登陆,那么不对于标识了LoginAllow的方法就不需要验证了
            object[] attrs = filterContext.ActionDescriptor.GetCustomAttributes(typeof(LoginAllowAttribute), true);
            // 是否是LoginAllow
            var ViewMethod = attrs.Length == 1;
            return ViewMethod;
        }

        #endregion

    }
















    /// <summary>
    /// [Anonymous] 匿名访问标记
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class AnonymousAttribute : Attribute
    {
    }



    /// <summary>
    /// [LoginAllow] 代表该方法可以允许登录用户都能访问
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class LoginAllowAttribute : Attribute
    {
    }



    /// <summary>
    /// [CheckUserRole] 表示当前Action请求为一个具体的功能页面，必须进行权限验证
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class CheckUserRoleAttribute : Attribute
    {
    }












}
